#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netinet/ip.h>

#include <arpa/inet.h>
#include <string>
#include <vector>
#include <iostream>

/**
 *  @author Kristina Kurian
 *  @usage serv
 *  @date 06-10-2011
*/
	
/**
 * TODO: 
 * 1. initialise vectors to consmer
 * 2. make vector in deserializable 
*/

#define BUFFER 1024
#define SERV_PORT 9877

//int type = -1;

class SerializableObject {
	public:
		virtual bool deserialize(const std::string& value) = 0;
                virtual std::string getData() = 0;
};

class SubclassA : public SerializableObject {
	private:
		std::string s;
	public:
		static std::vector <SubclassA> a;
		static void Instance()  {
    			//if(!a) 
				a = std::vector<SubclassA>();
    		}
                SubclassA() {}
                SubclassA(std::string t) {
		        s = t;
		}
		bool deserialize(const std::string& value) {
			if (value.substr(0,2).compare("1:")==0) {
				int length = atoi(value.substr(2,3).c_str());
				s = value.substr(4, length);
				a.push_back(SubclassA(s));
				return true;
			}
			return false;
		}
                std::string getData() {
		        return s;
                }
};

class SubclassB : public SerializableObject {
	private:
		std::string s;
	public:	
                static std::vector <SubclassB> b;
                SubclassB() {}
                SubclassB(std::string t) {
                        s = t;
                }
		bool deserialize(const std::string& value) {
			if (value.substr(0,2).compare("2:") == 0) {
				int length = atoi(value.substr(2,3).c_str());
				s = value.substr(4, length);
				b.push_back(SubclassB(s));
				return true;
			}
			return false;	
		}
                std::string getData() {
		        return s;
                }
};

class SubclassC : public SerializableObject {
	private:
		std::string s;
	public:	
                static std::vector <SubclassC> c;
                SubclassC() {}
                SubclassC(std::string t) {
                        s = t;
                }
        	bool deserialize(const std::string& value) {
			if (value.substr(0,2).compare("3:") == 0) {
				int length = atoi(value.substr(2,3).c_str());
				s = value.substr(4, length);
				c.push_back(SubclassC(s));
				return true;
			}
			return false;	
		}
                std::string getData() {
		        return s;
                }
		
		void execute() {
			std::cout << "SubclassC" << std::endl;
		}
};


//std::vector <SubclassA> SubclassA::a = std::vector<SubclassA>();
std::vector <SubclassB> SubclassB::b = std::vector<SubclassB>();
std::vector <SubclassC> SubclassC::c = std::vector<SubclassC>();


class Consumer {
	public:
		virtual void consume() = 0;
};

class ConclassA : public Consumer {
	public:	
		ConclassA() {}
		ConclassA(std::vector<SerializableObject *> &prot) {
		 	prot.push_back(new SubclassA());
			SubclassA::Instance();
		}
        	void consume() {
			while(SubclassA::a.size() > 0) {
			  std::cout << "1 - " << SubclassA::a.back().getData() << std::endl;
			  SubclassA::a.pop_back();
			}
		}
        
};

class ConclassB : public Consumer {
	public:	
		ConclassB(std::vector<SerializableObject *> &prot) {
			prot.push_back(new SubclassB());
		}
        	
		void consume() {
			while(SubclassB::b.size() > 0) {
			  std::cout << "2 - " << SubclassB::b.back().getData() << std::endl;				
			  SubclassB::b.pop_back();
			}
		}
};

class ConclassC : public Consumer {
	public:	
		ConclassC(std::vector<SerializableObject *> &prot) {
			prot.push_back(new SubclassC());
		}
        	
		void consume() {
			while(SubclassC::c.size() > 0) {
			  SubclassC c = SubclassC::c.back();
			  std::cout << "3 - " << c.getData() << std::endl;				
			  c.execute();	
			  SubclassC::c.pop_back();
			}
		}
};

void receiveAndUnpackData(const std::vector<SerializableObject* >& prototype, char *buf) {
	bool res = false;
	std::string value = buf;
	for (int i = 0; i < prototype.size(); ++i) {
		res = prototype[i]->deserialize(value);
		if (res) {
			break;		
		}
	}
}

void printData(const std::vector<Consumer*> &consumer) {
	for (int i = 0; i < consumer.size(); ++i) {
		consumer[i]->consume();
	}
}

void init(std::vector<SerializableObject *> &prototype,	std::vector<Consumer *> &consumer) {
	consumer.push_back(new ConclassA(prototype));
	consumer.push_back(new ConclassB(prototype));
	consumer.push_back(new ConclassC(prototype));
}

int main(int argc, char ** argv) {
	int sock;
	int listenfd;
	struct sockaddr_in addr;
	char buf[BUFFER];
	int bytes_read;
	std::vector<SerializableObject *> prototype;
	std::vector<Consumer *> consumer;
	
	init(prototype, consumer);
	listenfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (listenfd == -1) {
		printf("ERROR: Failed to create socket\n");
		return 1;
	}


	addr.sin_family = AF_INET;
  	addr.sin_addr.s_addr = htonl(INADDR_ANY);
  	addr.sin_port = htons(SERV_PORT);	
	
	if (bind(listenfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
		printf("ERROR: failed to bind\n");
		close(listenfd);
		return 1;
	}

	struct sockaddr from_addr;
	int addr_len = sizeof(from_addr);
	while (1) {
		bytes_read = recvfrom(listenfd, (void *)buf, BUFFER, 0, &from_addr, (socklen_t*)&addr_len);

		if (bytes_read < 0) {
			printf("ERROR: Failed to read\n");
			return 1;	
		}
		receiveAndUnpackData(prototype, buf);
		printData(consumer);
	}
	close(sock);
	return 0;
}
